package com.yuwubao.hz_International.services.impl

import com.fasterxml.jackson.databind.ObjectMapper
import com.yuwubao.hz_International.entities.*
import com.yuwubao.hz_International.entities.repository.*
import com.yuwubao.hz_International.entities.vo.*
import com.yuwubao.hz_International.exception.MoneyException
import com.yuwubao.hz_International.exception.SysException
import com.yuwubao.hz_International.services.AppService
import com.yuwubao.hz_International.util.MD5
import com.yuwubao.hz_International.util.TypeConst
import com.yuwubao.hz_International.util.genQrCode
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.domain.Specification
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.math.BigDecimal
import java.text.SimpleDateFormat
import java.util.*
import javax.annotation.Resource
import javax.persistence.criteria.Path

@Service
@Transactional
open class AppServiceImpl : AppService {
    @Resource
    private lateinit var storeDao: StoreRepository
    @Resource
    private lateinit var bannerDao: BannerImgRepository
    @Resource
    private lateinit var acountDao: AcountDetailRepository
    @Resource
    private lateinit var userDao: ConsumerRepository
    @Resource
    private lateinit var rechargeDao: RechargeConfigRepository
    @Resource
    private lateinit var inviteDao: InviteRewardsConfigRepository
    @Resource
    private lateinit var processDao: ProceedsConfigRepository

    @Resource
    private lateinit var giftFansDao: GiftFansRepo

    @Resource
    private lateinit var welfareTotalDao: WelfareTotalRepo

    @Resource
    private lateinit var welfareConfigRepo: WelfareConfigRepository

    @Resource
    lateinit var storeCollectionRepo: StoreCollectionRepo

    @Resource
    lateinit var giftConfigRepository: GiftConfigRepository

    override fun getStore(index: Int, size: Int): Page<StoreEntity>? {
        val order1 = Sort.Order(Sort.Direction.DESC, "stick")
        val order2 = Sort.Order(Sort.Direction.DESC, "stickTime")
//        val sort = Sort(Sort.Direction.DESC, "createTime")
        val sort = Sort(order1, order2)
        val pageable = PageRequest(index - 1, size, sort)
        return storeDao.findAll(pageable)
    }

    override fun getBanner(): List<String> {
        return bannerDao.all_banner()
    }

    override fun consumptionVos(userId: Int, index: Int, size: Int, type: Int): Page<ConsumptionVo>? {
        userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val sort = Sort(Sort.Direction.DESC, "createTime")
        val pageable = PageRequest(index - 1, size, sort)
        if (type != 4) {
            val spec: Specification<AcountDetailEntity> = Specification { root, criteriaQuery, criteriaBuilder ->
                val p = criteriaBuilder.conjunction()
                val p0: Path<String> = when (type) {
                    0 -> root["money"]
                    1 -> root["welfare"]
                    2 -> root["bonouse"]
                    else -> root["gift"]
                }
                val p1: Path<Int> = root["consumerId"]
                p.expressions.add(criteriaBuilder.notEqual(p0, "0"))
                p.expressions.add(criteriaBuilder.equal(p1, userId))
                p
            }
            val vos = acountDao.findAll(spec, pageable)
            return vos.map { it ->
                val entity = ConsumptionVo()
                entity.type = if (type == 2 && it.useType == 13) "充值奖励" else getType(it.useType)
                entity.money = when (type) {
                    0 -> it.money
                    2 -> it.bonouse
                    1 -> it.welfare
                    else -> it.gift
                }
                entity.createTime = it.createTime
                entity
            }
        } else {
            val spec: Specification<StoreCollection> = Specification { root, criteriaQuery, criteriaBuilder ->
                val p = criteriaBuilder.conjunction()
                val p0: Path<Int> = root["storeId"]
                p.expressions.add(criteriaBuilder.equal(p0, userId))
                p
            }
            val pages = storeCollectionRepo.findAll(spec, pageable)
            return pages.map { it ->
                val entity = ConsumptionVo()
                entity.createTime = it.createTime
                entity.money = "+" + retain(it.money)
                entity.type = it.phone.substring(0, 3) + "****" + it.phone.substring(7, it.phone.length)
                entity
            }
        }
    }

    //充值
    override fun recharge(userId: Int, money: Double) {
        val user = userDao.findOne(userId)
        val rechargeConfig = rechargeDao.findLast() ?: throw SysException()
        val trans_money = retain(BigDecimal(money))
        val integral = retain(trans_money?.multiply(rechargeConfig.money))
        val detail = AcountDetailEntity()
        detail.consumerId = userId
        detail.createTime = Date()
        detail.currentMoney = user.money.add(trans_money)
        detail.currentBonous = user.bonous.add(integral)
        detail.currentGift = user.giftMoney
        detail.currentWelfare = user.welfareMoney
        detail.type = TypeConst.coin.consumption
        detail.useType = TypeConst.coinUseType.online_top_up
        detail.money = "+" + money
        detail.welfare = "0"
        detail.bonouse = "+" + integral
        detail.gift = "0"
        detail.payType = TypeConst.payType.alipay
        detail.name = user.name
        acountDao.save(detail)
        /**
        消费金处理
         */
        user.money = user.money.add(trans_money)
        user.bonous = user.bonous.add(integral)
        userDao.save(user)
        if (user.invitePhone.isNotBlank()) {
            //假如有邀请人
            val invite = userDao.findByPhone(user.invitePhone)
            val inviteConfig = inviteDao.last ?: throw SysException()
//            val trans_gift = trans_money.divide(inviteConfig.rewardRatio)
            val trans_gift = retain(trans_money?.multiply(inviteConfig.rewardRatio.divide(BigDecimal(1000))))
            invite.giftMoney = invite.giftMoney.add(trans_gift)
            val invite_detail = AcountDetailEntity()
            invite_detail.createTime = Date()
            invite_detail.consumerId = invite.id
            invite_detail.currentMoney = user.money
            invite_detail.currentBonous = user.bonous
            invite_detail.currentWelfare = user.welfareMoney
            invite_detail.currentGift = invite.giftMoney
            invite_detail.type = TypeConst.coin.gift
            invite_detail.useType = TypeConst.coinUseType.friend
            invite_detail.money = "0"
            invite_detail.welfare = "0"
            invite_detail.bonouse = "0"
            invite_detail.gift = "+" + trans_gift
            invite_detail.name =invite.name
            //邀请人充值
            var fans = giftFansDao.findByPhone(invite.id, user.phone)
            if (fans != null) {
                fans.totalGift = fans.totalGift?.add(trans_gift)
            } else {
                fans = GiftFans()
                fans.totalGift = trans_gift
                fans.phone = user.phone
                fans.userId = invite.id
            }
            giftFansDao.save(fans)
            userDao.save(invite)
            acountDao.save(invite_detail)
        }
    }

    override fun getMyCoin(userId: Int, type: Int): MyCoin {
        val user = userDao.findOne(userId)
        val myCoin = MyCoin()
        when (type) {
            0 -> {
                myCoin.money = user.money.toDouble()
                val entity = rechargeDao.findLast()
                myCoin.rate = entity.money.toDouble()
                myCoin.tips = entity.tip
                myCoin.minMoney = entity.minRechargeMoney.toDouble()
            }
            1 -> {
                myCoin.money = user.bonous.toDouble()
            }
            2 -> {
                myCoin.money = user.welfareMoney.toDouble()
                myCoin.yesterday = user.welfareYesterdayMoney.toDouble()
                myCoin.total = user.welfareProfitMoney.toDouble()
            }
            else -> {
                myCoin.money = user.giftMoney.toDouble()
            }
        }
        return myCoin
    }

    override fun findMyQrCode(userId: Int): MyQrCode {
        val user = userDao.findOne(userId) ?: throw NullPointerException("用户不存在")
        if (user.isStore != 1) throw NullPointerException("用户不是商户")
        val store = storeDao.findByConsumerId(userId) ?: throw NullPointerException("商户不存在")
        val totalMoney: BigDecimal = storeCollectionRepo.findTotalMoney(userId)
        val myQrcode = MyQrCode()
        myQrcode.totalMoney = totalMoney.toDouble()
        myQrcode.url = store.qrUrl
        return myQrcode
    }

    override fun beforeRecharge(userId: Int, type: Int): MyCoin {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val rechargeConfig = rechargeDao.findLast() ?: throw SysException()
        val myCoin = MyCoin()
        myCoin.money = user.money.toDouble()
        myCoin.minMoney = rechargeConfig.minRechargeMoney.toDouble()
        myCoin.tips = when (type) {
            0 -> rechargeConfig.tip
            else -> rechargeConfig.conversionRatioTip
        }
        myCoin.rate = when (type) {
            0 -> rechargeConfig.money.toDouble()
            else -> rechargeConfig.bonous.toDouble()
        }
        return myCoin
    }

    override fun toWelfare(userId: Int, money: Double) {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        if (user.money < BigDecimal(money)) throw MoneyException()
        user.money = user.money.subtract(BigDecimal(money))
        user.welfareMoney = user.welfareMoney.add(BigDecimal(money))
        val detail = AcountDetailEntity()
        detail.consumerId = userId
        detail.createTime = Date()
        detail.currentMoney = user.money
        detail.currentGift = user.giftMoney
        detail.currentWelfare = user.welfareMoney
        detail.currentBonous = user.bonous
        detail.type = TypeConst.coin.welfare
        detail.useType = TypeConst.coinUseType.to_welfare
        detail.welfare = "+" + money
        detail.money = "-" + money
        detail.bonouse = "0"
        detail.gift = "0"
        detail.payType = 0
        detail.name = user.name
        acountDao.save(detail)
        userDao.save(user)
    }

    override fun getMyCoins(userId: Int): MyCoins {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val myCoins = MyCoins()
        myCoins.money = user.money.toDouble()
        myCoins.bonous = user.bonous.toDouble()
        myCoins.welfare = user.welfareMoney.toDouble()
        myCoins.gift = user.giftMoney.toDouble()
        return myCoins

    }

    override fun getCustomer(): String {
        return processDao.last
    }

    override fun toRedeem(userId: Int, money: Double) {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val trans_money = retain(BigDecimal(money))
        if (user.money < trans_money) throw Exception("兑换的消费金超过当前余额")
        val rechargeConfig = rechargeDao.findLast() ?: throw SysException()
        user.money = user.money.subtract(trans_money)
        val redeem = retain(trans_money?.multiply(rechargeConfig.bonous))
        user.bonous = user.bonous.add(redeem)

        val detail = AcountDetailEntity()
        detail.consumerId = userId
        detail.currentBonous = user.bonous
        detail.currentWelfare = user.welfareMoney
        detail.currentGift = user.giftMoney
        detail.currentMoney = user.money
        detail.createTime = Date()
        detail.type = TypeConst.coin.integral
        detail.useType = TypeConst.coinUseType.to_integral
        detail.money = "-" + money
        detail.welfare = "0"
        detail.bonouse = "+" + redeem
        detail.gift = "0"
        detail.name = user.name
        detail.payType = 0
        acountDao.save(detail)
        userDao.save(user)
    }

    override fun getMyFans(userId: Int, index: Int, size: Int): HashMap<String, Any> {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val totalGift = giftFansDao.findByUserId(userId)
        val config = inviteDao.last

        val pageable: Pageable = PageRequest(index - 1, size)
        val pages = giftFansDao.findByUserId(userId, pageable).map { it ->
            val myFansVo = MyFansVo()
            myFansVo.name = it.phone.substring(0, 3) + "****" + it.phone.substring(7, it.phone.length)
            myFansVo.gift = it.totalGift.toString()
            myFansVo
        }
        val map = HashMap<String, Any>()
        map["total"] = totalGift
        map["page"] = pages
        map["tips"] = config.activityRules
        return map
    }

    override fun createGiftFans(fans: GiftFans) {
        giftFansDao.save(fans)
    }

    override fun withdrawal(userId: Int, money: Double) {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val num = BigDecimal(money)
        if (num > user.welfareMoney) throw NullPointerException("余额不足")
        val welfareTotal = welfareTotalDao.findToday() ?: throw NullPointerException("系统维护，暂无可提取福利金")
        if (num > welfareTotal.withdrawal) throw Exception("超出今天可提现额度")
        val transMoney = retain(num)
        user.welfareMoney = user.welfareMoney.subtract(transMoney)
        user.money = user.money.add(transMoney)


        val detail = AcountDetailEntity()
        detail.consumerId = userId
        detail.createTime = Date()
        detail.payType = 0
        detail.gift = "0"
        detail.bonouse = "0"
        detail.money = "+" + transMoney
        detail.welfare = "-" + transMoney
        detail.useType = TypeConst.coinUseType.to_consumption
        detail.type = TypeConst.coin.welfare
        detail.currentMoney = user.money
        detail.currentGift = user.giftMoney
        detail.currentWelfare = user.welfareMoney
        detail.currentBonous = user.bonous
        detail.name = user .name

        welfareTotal.withdrawal = welfareTotal.withdrawal?.subtract(transMoney)
        welfareTotalDao.save(welfareTotal)
        acountDao.save(detail)
        userDao.save(user)
    }


    override fun beforeWithdrawal(userId: Int): WithdrawalVo {
        userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val welfareConfig = welfareConfigRepo.last
        val welfareTotal = welfareTotalDao.findToday()
        val withdrawal = WithdrawalVo()
        if (welfareTotal == null) {
            withdrawal.msg = "系统维护，暂无可提取福利金"
        } else
            withdrawal.money = welfareTotal.withdrawal?.toDouble()
        withdrawal.tips = welfareConfig.tip
        return withdrawal
    }

    override fun pay(userId: Int, qrCode: Int, money: Double) {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val store = userDao.findOne(qrCode) ?: throw  NullPointerException("商户信息异常")
        if (store.isStore != 1) throw NullPointerException("商户信息异常")
        if (BigDecimal(money) > user.money) throw MoneyException()
        val transMoney = retain(BigDecimal(money))
        user.money = user.money.subtract(transMoney)
        store.money = store.money.add(transMoney)

        val userDetail = AcountDetailEntity()
        userDetail.consumerId = userId
        userDetail.currentBonous = user.bonous
        userDetail.currentWelfare = user.welfareMoney
        userDetail.currentGift = user.giftMoney
        userDetail.currentMoney = user.money
        userDetail.type = TypeConst.coin.consumption
        userDetail.useType = TypeConst.coinUseType.online_pay
        userDetail.money = "-" + transMoney
        userDetail.welfare = "0"
        userDetail.bonouse = "0"
        userDetail.gift = "0"
        userDetail.payType = 0
        userDetail.name = user.name
        userDetail.createTime = Date()

        val storeDetail = AcountDetailEntity()
        storeDetail.consumerId = store.id
        storeDetail.currentMoney = store.money
        storeDetail.currentGift = store.giftMoney
        storeDetail.currentWelfare = store.welfareMoney
        storeDetail.currentBonous = store.bonous
        storeDetail.type = TypeConst.coin.consumption
        storeDetail.useType = TypeConst.coinUseType.online_collection
        storeDetail.money = "+" + transMoney
        storeDetail.bonouse = "0"
        storeDetail.welfare = "0"
        storeDetail.gift = "0"
        storeDetail.payType = 0
        storeDetail.createTime = Date()
        storeDetail.name = store.name
        /**
         * 生成订单信息
         */
        val storeCollection = StoreCollection()
        storeCollection.money = transMoney
        storeCollection.payId = userId
        storeCollection.storeId = store.id
        storeCollection.sn = UUID.randomUUID().toString().replace("-", "")
        storeCollection.phone = user.phone

        userDao.save(user)
        userDao.save(store)
        acountDao.save(storeDetail)
        acountDao.save(userDetail)
        storeCollectionRepo.save(storeCollection)
    }

    override fun getMyCollections(userId: Int, type: Int, index: Int, size: Int): Page<MyCollectionVo> {
        val user = userDao.findOne(userId) ?: throw  NullPointerException("用户不存在")
        val pageable: Pageable = PageRequest(index - 1, size)
        val spec: Specification<StoreCollection> = Specification { root, criteriaQuery, criteriaBuilder ->
            val p = criteriaBuilder.conjunction()
            val p0: Path<Int> = root["storeId"]
            p.expressions.add(criteriaBuilder.equal(p0, userId))
            p
        }
        val pages = storeCollectionRepo.findAll(spec, pageable)
        return pages.map { it ->
            val myCollectionVo = MyCollectionVo()
            myCollectionVo.createTime = it.createTime
            myCollectionVo.money = "+" + it.money
            myCollectionVo.phone = it.phone.substring(0, 3) + "****" + it.phone.substring(7, it.phone.length)
            myCollectionVo
        }
    }

    override fun updatePassword(phone: String, password: String) {
        val user = userDao.findByPhone(phone) ?: throw NullPointerException("该手机号未注册")
        val pwd = MD5.md5(password)
        user.password = pwd
        userDao.save(user)
    }

    override fun getAllWelfare(): WelfareVo {
        val vo = WelfareVo()
        vo.total = userDao.allWelfare
        vo.config = welfareConfigRepo.last
        return vo
    }

    override fun save(welfareTotal: WelfareTotal) {
        welfareTotalDao.save(welfareTotal)
    }


    override fun hasWelfareUser(): List<ConsumerEntity> {
        return userDao.hasWelfareUser()
    }

    override fun saveUser(hasWelfareUser: List<ConsumerEntity>) {
        userDao.save(hasWelfareUser)
    }

    override fun hasGiftUser(): List<ConsumerEntity> {
        return userDao.hasGiftUser()
    }

    override fun welfareConfig(): WelfareConfigEntity? {
        return welfareConfigRepo.last
    }

    override fun giftConfig(): GiftConfigEntity? {
        return giftConfigRepository.last
    }

    override fun saveDetail(list: MutableList<AcountDetailEntity>) {
        acountDao.save(list)
    }

    override fun createQrCode(storeEntity: StoreEntity): String {
        val mapper = ObjectMapper()
        val map = hashMapOf<String, Any>()
        map["name"] = storeEntity.name
        map["id"] = storeEntity.consumerId
        return genQrCode(mapper.writeValueAsString(map))
    }

    override fun hasBonousUser(): List<ConsumerEntity> = userDao.hasBonousUser()
    override fun getMoneyList(name: String, start: String, end: String, index: Int, size: Int, type: Int): Page<MoneyVo> {
        val pageable: Pageable = PageRequest(index - 1, size)
        val sdf = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")

        val specification: Specification<AcountDetailEntity> = Specification { root, query, cb ->
            var p = cb.conjunction()
            if (name.isNotBlank()) {
                val path: Path<String> = root["name"]
                p.expressions.add(cb.like(path, "%$name%"))

            }
            if (start.isNotBlank()) {
                val path: Path<Date> = root["createTime"]
                println("path:$path")
                p.expressions.add(cb.greaterThanOrEqualTo(path, sdf.parse(start)))
            }
            if (end.isNotBlank()) {
                val path: Path<Date> = root["createTime"]
                p.expressions.add(cb.lessThanOrEqualTo(path, sdf.parse(end)))
            }
            when(type){
                0 -> {
                    val path :Path<String> = root["money"]
                    p.expressions.add(cb.notEqual(path,"0"))
                }
                1->{
                    val path:Path<String> = root["welfare"]
                    p.expressions.add(cb.notEqual(path,"0"))
                }
                2->{
                    val path:Path<String> = root["bonouse"]
                    p.expressions.add(cb.notEqual(path,"0"))
                }
                else->{
                    val path:Path<String> = root["gift"]
                    p.expressions.add(cb.notEqual(path,"0"))
                }
            }
                    p
        }
        val vo = acountDao.findAll(specification, pageable)
        return vo.map { it ->
            val moneyVo = MoneyVo()
            moneyVo.time = it.createTime
            moneyVo.name = it.name
            moneyVo.money = when (type) {
                0 -> it.money
                1 -> it.welfare
                2 -> it.bonouse
                else -> it.gift
            }

            moneyVo
        }


    }

    override fun updateName() {
        val list = acountDao.findAll()
        list.map { it ->
            val user = userDao.findOne(it.consumerId)
            if (user != null)
                it.name = user.name
        }
        acountDao.save(list)
    }
}

fun retain(num: BigDecimal?): BigDecimal? {
    return num?.setScale(2, BigDecimal.ROUND_HALF_DOWN)
}
